/*
 * This class handles the camera.
 */

package com.android.camtube;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.hardware.Camera;
import android.media.MediaRecorder;
import android.os.Environment;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;



public class CameraHandler {
	
/**************************/
/*****   Constants   *****/
/**************************/
	
	// Used for display orientation
	public static final int DSP_ANGLE_0         =   0;
	public static final int DSP_ANGLE_90        =  90;
	public static final int DSP_ANGLE_180       = 180;
	public static final int DSP_ANGLE_270       = 270;
	public static final int CAPTURE_FPS         =  25;
	public static final int CAPTURE_MAXDURATION = 20000;
	public static final int CAPTURE_MAXFILESIZE = 500000;
	
	
	
/**************************/
/*****   Attributes   *****/
/**************************/

	private Camera camera;                // Connect with the camera service
	private byte[] rawBuffer, jpegBuffer; // Hold frames            
	private Camera.Parameters params;     // Camera parameters
	private MediaRecorder recorder;       // Used to record videos
	
	// Gets a raw image from takePicture
	private Camera.PictureCallback rawPicture = new Camera.PictureCallback() {
		public void onPictureTaken(byte[] data, Camera camera) {
			rawBuffer = data;
		}
	};
	
	// Gets a jpg compressed picture from takePicture
	private Camera.PictureCallback jpegPicture = new Camera.PictureCallback() {
		public void onPictureTaken(byte[] data, Camera camera) {
			jpegBuffer = data;
			
        	if(jpegBuffer != null)
        		Log.d("D_CAMTUBE", "Picture length: " + jpegBuffer.length);
        	else
        		Log.d("D_CAMTUBE", "Picture length: null");
        	
        	// Uses picture
        	boolean storageAvailable = false;
        	boolean storageWriteable = false;
        	String state = Environment.getExternalStorageState();
        	
        	if(Environment.MEDIA_MOUNTED.equals(state)) {
        		storageAvailable = storageWriteable = true;
        	}
        	else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        	    // We can only read the media
        		storageAvailable = true;
        	    storageWriteable = false;
        	}
        	else {
        	    // Something else is wrong. It may be one of many other states, but all we need
        	    //  to know is we can neither read nor write
        		storageAvailable = storageWriteable = false;
        	}
        	
        	if( (storageAvailable == true) && (storageWriteable == true) ) {
        		//File file = new File(Environment.DIRECTORY_PICTURES, "teste.jpg");
        		//File file =  new File(Environment.getExternalStorageDirectory().toString() + "teste.jpg");
        		//File file =  new File("/sdcard/DCIM/Camera/teste.jpg");
        		FileOutputStream out = null;
				try {
					out = new FileOutputStream(String.format("/sdcard/DCIM/Camera/%d.jpg", System.currentTimeMillis()));
					out.write(data);
	        		out.close();
	        		
				} catch (IOException e) {
					// TODO Auto-generated catch block
					Log.d("D_CAMTUBE", "Cannot write data!");
					e.printStackTrace();
				}
        		
        	}
        	else {
        		// Cannot save picture
        		Log.d("D_CAMTUBE", "Cannot save picture!");

        	}
        	
        	// Restart preview
        	startPreview();
			
		}
	};
	
	
	
	
	
/***********************/
/*****   Methods   *****/
/***********************/
	
	/*
	 * Constructor
	 */
	CameraHandler() {
		camera   = Camera.open();
		params   = camera.getParameters();
		recorder = new MediaRecorder();
		
	}

	
	/*
	 * Get camera parameters
	 */
	public CameraParameters getParameters() {
		return new CameraParameters(params.getColorEffect(),
				params.getFlashMode(),
				params.getFocusMode(),
				params.getPictureSize(),
				params.getPreviewSize(),
				params.getSceneMode(),
				params.getWhiteBalance(),
				/*params.getZoom()*/0);
	}
	
	
	/*
	 * Set camera parameters
	 * CameraParameters attributes with null value and zoom with
	 * -1 value are not set
	 */
	public void setParameters(CameraParameters params) {
		if(params.colorEffect != null)
			this.params.setColorEffect(params.colorEffect);
		if(params.flashMode != null)
			this.params.setFlashMode(params.flashMode);
		if(params.focusMode != null)
			this.params.setFocusMode(params.focusMode);
		if(params.pictureSize != null)
			this.params.setPictureSize(params.pictureSize.width, params.pictureSize.height);
		if(params.previewSize != null) 
			this.params.setPreviewSize(params.previewSize.width, params.previewSize.height);
		if(params.sceneMode != null) 
			this.params.setSceneMode(params.sceneMode);
		if(params.whiteBalance != null) 
			this.params.setWhiteBalance(params.whiteBalance);
		if(params.zoom > -1)
			//this.params.setZoom(params.zoom);
		
		this.params = camera.getParameters();
	}
	
	
	/*
	 * Get supported parameters
	 * Return a list of all supported parameters value from
	 * a given parameter type. For SUPPORTED_ZOOM parameter type
	 * the list contain just the maximum zoom value
	 */
	public void getSupportedParameters(CameraParameters cparams) {		
		cparams.supportedColorEffects  = params.getSupportedColorEffects();
		cparams.supportedFlashModes    = params.getSupportedFlashModes();
		cparams.supportedFocusModes    = params.getSupportedFocusModes();
		cparams.supportedPicturesSizes = params.getSupportedPictureSizes();
		cparams.supportedPreviewSizes  = params.getSupportedPreviewSizes();
		cparams.supportedScenesModes   = params.getSupportedSceneModes();
		cparams.supportedWhiteBalance  = params.getSupportedWhiteBalance();
		//cparams.supportedZoom          = params.isZoomSupported();

	}

	
	/*
	 * Start the camera preview
	 */
	public void startPreview() {
		camera.startPreview();
	}

	
	/*
	 * Stop the camera preview
	 */
	public void stopPreview() {
		camera.stopPreview();
	}
	
	
	/*
	 * Lock the camera
	 */
	public void lock() {
		camera.lock();
	}
	
	
	/*
	 * Unlock the camera
	 */
	public void unlock() {
		camera.unlock();
	}
	
	
	
	/*
	 * Release the camera
	 */
	public void release() {
		camera.release();
	}
	
	
	/*
	 * Get current frame size
	 */
	public Camera.Size getSize() {
		return params.getPictureSize();
	}
	
	
	/*
	 * Set the surface used to camera preview. It must be
	 * set before taking pictures or recording.
	 */
	public void setPreviewDisplay(SurfaceHolder holder) throws IOException {
		camera.setPreviewDisplay(holder);
	}
	
	
	/*
	 * Change the angle of the display
	 */
	public void setDisplayOrientation(int angle) {
		//camera.setDisplayOrientation(angle);
	}
	
	
	/*
	 * 
	 */
	public void takePicture() {
		camera.takePicture(null, rawPicture, jpegPicture);

	}
	
	
	public byte[] getRawPicture() {
		return rawBuffer;
	}
	
	
	public byte[] getJPEGPicture() {
		return jpegBuffer;
	}
	
	
	
	public boolean startRecording(String pathName, Surface sv) throws IllegalStateException, IOException {
		
		try {
			camera.unlock();

			recorder = new MediaRecorder();

			recorder.setCamera(camera);
			recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
			recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

			recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);

			recorder.setMaxDuration(CAPTURE_MAXDURATION);

			recorder.setOutputFile(pathName);

			recorder.setVideoFrameRate(CAPTURE_FPS);
			recorder.setVideoSize(getSize().width, getSize().height);

			recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
			recorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);

			recorder.setPreviewDisplay(sv);

			recorder.setMaxFileSize(CAPTURE_MAXFILESIZE);

			recorder.prepare();
			recorder.start();

			return true;
		} catch (IllegalStateException e) {
			//Log.e(TAG,e.getMessage());
			e.printStackTrace();
			return false;
		} catch (IOException e) {
			//Log.e(TAG,e.getMessage());
			e.printStackTrace();
			return false;
		}
		
	}
	
	
	public void stopRecording() throws IOException {
		recorder.stop();
		recorder.reset();
		recorder.release();
		camera.lock();
	}

}

